/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.calendar.event;

import java.util.Date;
import java.util.TimeZone;

import org.zkoss.json.JSONArray;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.out.AuSetAttribute;
import org.zkoss.zk.mesg.MZk;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.Clients;

import cn.easyplatform.web.ext.calendar.Calendars;
import cn.easyplatform.web.ext.calendar.api.CalendarEvent;
import cn.easyplatform.web.ext.calendar.impl.SimpleCalendarEvent;
import cn.easyplatform.web.ext.calendar.impl.Util;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class CalendarsEvent extends Event implements CalendarEvent {
	private static final long serialVersionUID = 20090331171731L;

	public static final String ON_EVENT_CREATE = "onEventCreate";
	public static final String ON_EVENT_EDIT = "onEventEdit";
	public static final String ON_EVENT_UPDATE = "onEventUpdate";
	public static final String ON_DAY_CLICK = "onDayClick";
	public static final String ON_WEEK_CLICK = "onWeekClick";
	// since 2.1.5
	public static final String ON_EVENT_TOOLTIP = "onEventTooltip";

	private Date _beginDate;

	private Date _endDate;

	private CalendarEvent _ce;

	private final int _x, _y, _dtwd, _dthgh;

	public CalendarsEvent(String name, Component target, CalendarEvent ce,
			Date beginDate, Date endDate, int x, int y, int dtwd, int dthgh) {
		super(name, target);
		_ce = ce;
		_beginDate = beginDate;
		_endDate = endDate;
		_x = x;
		_y = y;
		_dtwd = dtwd;
		_dthgh = dthgh;
		if (_ce != null && _beginDate != null && _endDate != null) {
			SimpleCalendarEvent sce = (SimpleCalendarEvent) _ce;
			sce.setBeginDate(_beginDate);
			sce.setEndDate(_endDate);
		}
		clear(target, true);
	}

	/**
	 * Creates an instance of {@link Event} based on the specified request.
	 */
	public static CalendarsEvent getCreateEvent(AuRequest request) {
		final JSONArray data = (JSONArray) request.getData().get("data");
		final Calendars cmp = verifyEvent(request, data, 6);
		TimeZone tz = cmp.getDefaultTimeZone();
		Date eventBegin = Util.fixDSTTime(tz, new Date(getLong(data.get(0))));
		Date eventEnd = Util.fixDSTTime(tz, new Date(getLong(data.get(1))));

		return new CalendarsEvent(ON_EVENT_CREATE, cmp, null, eventBegin,
				eventEnd, getInt(data.get(2)), getInt(data.get(3)),
				getInt(data.get(4)), getInt(data.get(5)));
	}

	public static CalendarsEvent getEditEvent(AuRequest request) {
		final JSONArray data = (JSONArray) request.getData().get("data");
		final Calendars cmp = verifyEvent(request, data, 5);

		CalendarEvent ce = cmp
				.getCalendarEventById(String.valueOf(data.get(0)));

		if (ce == null)
			return null;

		return new CalendarsEvent(ON_EVENT_EDIT, cmp, ce, null, null,
				getInt(data.get(1)), getInt(data.get(2)), getInt(data.get(3)),
				getInt(data.get(4)));
	}

	public static CalendarsEvent getUpdateEvent(AuRequest request) {
		final JSONArray data = (JSONArray) request.getData().get("data");
		final Calendars cmp = verifyEvent(request, data, 7);

		CalendarEvent ce = cmp
				.getCalendarEventById(String.valueOf(data.get(0)));

		if (ce == null)
			return null;
		TimeZone tz = cmp.getDefaultTimeZone();
		Date eventBegin = Util.fixDSTTime(tz, new Date(getLong(data.get(1))));
		Date eventEnd = Util.fixDSTTime(tz, new Date(getLong(data.get(2))));

		return new CalendarsEvent(ON_EVENT_UPDATE, cmp, ce, eventBegin,
				eventEnd, getInt(data.get(3)), getInt(data.get(4)),
				getInt(data.get(5)), getInt(data.get(6)));
	}

	public static Event getClickEvent(AuRequest request, String cmd) {
		final JSONArray data = (JSONArray) request.getData().get("data");
		final Calendars cmp = verifyEvent(request, data, 1);

		return new Event(cmd, cmp, Util.fixDSTTime(cmp.getDefaultTimeZone(),
				new Date(getLong(data.get(0)))));
	}

	public static Event getTooltipEvent(AuRequest request) {
		final JSONArray data = (JSONArray) request.getData().get("data");
		final Calendars cmp = verifyEvent(request, data, 5);

		CalendarEvent ce = cmp
				.getCalendarEventById(String.valueOf(data.get(0)));

		if (ce == null)
			return null;

		return new CalendarsEvent(ON_EVENT_TOOLTIP, cmp, ce, null, null,
				getInt(data.get(1)), getInt(data.get(2)), getInt(data.get(3)),
				getInt(data.get(4)));
	}

	private static int getInt(Object obj) {
		return Integer.parseInt(String.valueOf(obj));
	}

	private static long getLong(Object obj) {
		return Long.parseLong(String.valueOf(obj));
	}

	private static Calendars verifyEvent(AuRequest request, JSONArray data,
			int size) {
		final Calendars cmp = (Calendars) request.getComponent();
		if (cmp == null)
			throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
					request);

		if (data == null || data.size() != size)
			throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] {
					data, request });
		return cmp;
	}

	/**
	 * Stops to clear the dragging ghost command from server to client.
	 * <p>
	 * Note: If the method is invoked, application developer has to invoke
	 * {@link #clearGhost()} to clear the dragging ghost.
	 */
	public void stopClearGhost() {
		clear(getTarget(), false);
	}

	/**
	 * Clears the dragging ghost from server to client.
	 * <p>
	 * The CalendarsEvent will clear the ghost by default, except invoking
	 * {@link #stopClearGhost()}.
	 */
	public void clearGhost() {
		clear(getTarget(), true);
	}

	/**
	 * Returns the update beginning date. If the event name is onEventEdit, null
	 * is assumed.
	 */
	public Date getBeginDate() {
		if (_ce != null)
			return _ce.getBeginDate();
		return _beginDate;
	}

	/**
	 * Returns the update end date. If the event name is onEventEdit, null is
	 * assumed.
	 */
	public Date getEndDate() {
		if (_ce != null)
			return _ce.getEndDate();
		return _endDate;
	}

	@Override
	public Object getId() {
		if (_ce != null)
			return _ce.getId();
		return null;
	}

	@Override
	public String getTitle() {
		if (_ce != null)
			return _ce.getTitle();
		return null;
	}

	@Override
	public String getContent() {
		if (_ce != null)
			return _ce.getContent();
		return null;
	}

	@Override
	public String getHeaderColor() {
		if (_ce != null)
			return _ce.getHeaderColor();
		return null;
	}

	@Override
	public String getContentColor() {
		if (_ce != null)
			return _ce.getContentColor();
		return null;
	}

	@Override
	public String getZclass() {
		if (_ce != null)
			return _ce.getZclass();
		return null;
	}

	@Override
	public boolean isLocked() {
		if (_ce != null)
			return _ce.isLocked();
		return false;
	}

	/**
	 * Returns the calendar event. If the event name is onEventCreate, null is
	 * assumed.
	 */
	public CalendarEvent getCalendarEvent() {
		return _ce;
	}

	/**
	 * Returns the x coordination of the mouse pointer relevant to the
	 * component.
	 */
	public final int getX() {
		return _x;
	}

	/**
	 * Returns the y coordination of the mouse pointer relevant to the
	 * component.
	 */
	public final int getY() {
		return _y;
	}

	/**
	 * Returns the pixel width of the client's desktop.
	 */
	public int getDesktopWidth() {
		return _dtwd;
	}

	/**
	 * Returns the pixel height of the client's desktop.
	 */
	public int getDesktopHeight() {
		return _dthgh;
	}

	/**
	 * @since 2.0-RC do smart update, send an attribute to js
	 * @param target
	 * @param isClear
	 */
	private void clear(Component target, boolean isClear) {
		Clients.response("cleardd" + target.getUuid(), new AuSetAttribute(
				target, "cleardd", Boolean.valueOf(isClear)));
	}
}
